//
// Created by WenYF on 2016/11/3.
//
#include "packet.h"
#include "util.h"



ifulaid *if_create_ulaid(byte *str, int len) {
    if (!str || len <= 0) {
        return NULL;
    } else {
        int index = if_str_indexof((char*)str, len, '/');
        ifulaid *uid = (ifulaid *) malloc (sizeof(ifulaid));
        if (index == NOT_FOUND_POSITION) {
            uid->uid = (char *) malloc (sizeof(char) * (len + 1));
            if_str_cpy_x(uid->uid, len, (char*)str);
        } else {
            uid->uid = (char *) malloc (sizeof(char) * (index + 1));
            if_str_cpy_x(uid->uid, index, (char*)str);

			uid->uid[index] = '\0';

            if (index + 1 < len) {
                uid->resource = str[index + 1];
            } else {
                uid->resource = '1';
            }
        }

        return uid;
    }
}

ifulaid *if_create_ulaid_x(char *u, char c) {
    if (!u) {
        return NULL;
    } else {
        ifulaid *uid = (ifulaid *) malloc (sizeof(ifulaid));
        uid->uid = if_str_clone(u);
        uid->resource = c;
        return uid;
    }
}

byte* if_ulaid_toBytes(ifulaid *uid, short *length) {
    if(!uid) {
        return NULL;
    } else {
        int len = if_str_len(uid->uid);
        byte *str = (byte*) malloc (sizeof(byte) * (len + 2));
        if_str_cpy_x((char*)str, len, uid->uid);
        str[len] = '/';
        str[len+1] = uid->resource;
        *length = (short) (len + 2);
        return str;
    }
}

void if_delete_ulaid(ifulaid *u) {
    if (u) {
        free(u->uid);
        free(u);
    }
}

ifsessionOpenPacket* if_create_sessionOpen_packet(byte type) {
    ifsessionOpenPacket *sessionPacket = (ifsessionOpenPacket *) malloc (
            sizeof(ifsessionOpenPacket));
    sessionPacket->extra = NULL;
    sessionPacket->from = NULL;
    sessionPacket->to = NULL;
    sessionPacket->id = -1;

    sessionPacket->protocolVersion = 0;
    sessionPacket->type = type;

    return sessionPacket;
}

ifsessionClosePacket* if_create_sessionClose_packet(byte type) {
    ifsessionClosePacket *sessionPacket = (ifsessionClosePacket *) malloc (
            sizeof(ifsessionClosePacket));
    sessionPacket->extra = NULL;
    sessionPacket->from = NULL;
    sessionPacket->to = NULL;
    sessionPacket->id = -1;

    sessionPacket->type = type;

    return sessionPacket;
}

ifmessage* if_create_message(char *title) {
    ifmessage *message = (ifmessage*) malloc (sizeof(ifmessage));
    message->from = NULL;
    message->to = NULL;
    message->id = -1;

    message->title = if_str_clone(title);
    message->body = NULL;

    return message;
}
ifevent* if_create_event(short eventType, byte queryType, int actionCode) {
    ifevent *event = (ifevent*) malloc (sizeof(ifevent));
    event->from = NULL;
    event->to = NULL;
    event->id = -1;
    event->eventType = eventType;
    event->type = queryType;
    event->actionCode = actionCode;
    event->body = NULL;
    return event;
}

// for inner
void if_delete_packet(ifpacketWrapper *packetWrapper) {
    if (packetWrapper) {
        switch (packetWrapper->type) {
            case PACKET_TYPE_SESSION_OPEN: {
                ifsessionOpenPacket *sessionPacket = (ifsessionOpenPacket *) packetWrapper->packet;
                if_delete_ulaid(sessionPacket->from);
                if_delete_ulaid(sessionPacket->to);
                free(sessionPacket->extra);
                free(sessionPacket);
                break;
            }
            case PACKET_TYPE_SESSION_CLOSE: {
                ifsessionClosePacket *sessionPacket = (ifsessionClosePacket *) packetWrapper->packet;
                if_delete_ulaid(sessionPacket->from);
                if_delete_ulaid(sessionPacket->to);
                free(sessionPacket->extra);
                free(sessionPacket);
                break;
            }
            case PACKET_TYPE_MESSAGE: {
                ifmessage *message = (ifmessage *) packetWrapper->packet;
                if_delete_ulaid(message->from);
                if_delete_ulaid(message->to);
                free(message->title);
                free(message->body);
                free(message);
                break;
            }
            case PACKET_TYPE_EVENT: {
                ifevent *event = (ifevent *) packetWrapper->packet;
                if_delete_ulaid(event->from);
                if_delete_ulaid(event->to);
                free(event->body);
                free(event);
                break;
            }
        }
    }
}

void if_delete_packet_x(void *packet, byte type) {
    if (packet) {
        switch (type) {
            case PACKET_TYPE_SESSION_OPEN: {
                ifsessionOpenPacket *sessionPacket = (ifsessionOpenPacket *) packet;
                if_delete_ulaid(sessionPacket->from);
                if_delete_ulaid(sessionPacket->to);
                free(sessionPacket->extra);
                free(sessionPacket);
                break;
            }
            case PACKET_TYPE_SESSION_CLOSE: {
                ifsessionClosePacket *sessionPacket = (ifsessionClosePacket *) packet;
                if_delete_ulaid(sessionPacket->from);
                if_delete_ulaid(sessionPacket->to);
                free(sessionPacket->extra);
                free(sessionPacket);
                break;
            }
            case PACKET_TYPE_MESSAGE: {
                ifmessage *message = (ifmessage *) packet;
                if_delete_ulaid(message->from);
                if_delete_ulaid(message->to);
                free(message->title);
                free(message->body);
                free(message);
                break;
            }
            case PACKET_TYPE_EVENT: {
                ifevent *event = (ifevent *) packet;
                if_delete_ulaid(event->from);
                if_delete_ulaid(event->to);
                free(event->body);
                free(event);
                break;
            }
        }
    }
}

static void* if_packet_common(ifulaid *from, ifulaid *to, int id, byte pakType, byte *content, int length, byte key) {
    byte *idBytes = if_intToByteArray(id);
    short fromLength = 0;
    byte *fromBytes = NULL;
    short toLength = 0;
    byte *toBytes = if_ulaid_toBytes(to, &toLength);
	int dataSize = 0;

	byte *allDataSizeBytes = NULL;
    byte *dataSizeBytes = NULL;

    void *buffer = NULL;
	int crc32 = -1;
	byte* crc32Byte = NULL;
    logD("toLength = %d", toLength);

    if (from) {
        fromBytes = if_ulaid_toBytes(from, &fromLength);
    }

    logD("fromLength = %d", fromLength);
    dataSize = 1 + 4 + 2 + toLength + 2 + fromLength + 4 + length + 4;
    dataSizeBytes = if_intToByteArray(length);
    allDataSizeBytes = if_intToByteArray(dataSize);

    buffer = if_buffer_new(dataSize +  6);
    // 头和长度位6
    // 头
    if_buffer_put(buffer, (byte)0xAA);
    if_buffer_put(buffer, (byte)0xDD);
    // 全部数据长度
    if_buffer_putBytes(buffer, allDataSizeBytes, 4);

    // 设置包类型
    if_buffer_put(buffer, pakType);
    // 设置id
    if_buffer_putBytes(buffer, idBytes, 4);
    // 设置接收者长度
    if_buffer_putBytes(buffer, if_shortToByteArray(toLength), 2);
    // 设置接收者
    if_buffer_putBytes(buffer, toBytes, toLength);
    // 设置发送者长度
    if_buffer_putBytes(buffer, if_shortToByteArray(fromLength), 2);
    // 设置发送者
    if_buffer_putBytes(buffer, fromBytes, fromLength);
    // 设置数据长度
    if_buffer_putBytes(buffer, dataSizeBytes, 4);
    // 设置数据
    if_buffer_putBytes(buffer, content, length);

	// 加密
	if_quick_encrypt_x(if_buffer_array(buffer), 6, dataSize - 4, key);

    // 得到校验码
    crc32 = if_calculate_CRC32(if_buffer_array(buffer), 6, dataSize - 4);
    logD("crc32 = %d", crc32);
    crc32Byte = if_intToByteArray(crc32);
    if_buffer_putBytes(buffer, crc32Byte, 4);

    if_buffer_flip(buffer);
    logD("buffer size = %d", if_buffer_remaining(buffer));

    free(idBytes);
    free(allDataSizeBytes);
    free(dataSizeBytes);
    free(crc32Byte);

    // start 2017/10/31，fix a low alloc memory bug by WenYF
    if (toBytes) {
        free(toBytes);
    }
    if (fromBytes) {
        free(fromBytes);
    }
    // end 2017/10/31，fix a low alloc memory bug by WenYF

    return buffer;
}

// 得到包buffer数据
void* if_packet_getBuffer(void *packet, byte packetType, byte key) {
    if (packet) {
        ifulaid *from = NULL;
        ifulaid *to = NULL;
        int id = -1;
        byte *data = NULL;
        int length = 0;
		void *buffer = NULL;

        switch (packetType) {
            case PACKET_TYPE_SESSION_OPEN: {
                // 这里都是要发给服务器的数据
                // 登陆
                int count = 0, i;
                ifsessionOpenPacket *sessionPacket = (ifsessionOpenPacket *) packet;
				int exlen = if_str_len(sessionPacket->extra);
                byte *extraLength = if_shortToByteArray(exlen);
				byte versionProtocol = 1;

                from = sessionPacket->from;
                to = sessionPacket->to;
                id = sessionPacket->id;

                length = 1 + 1 + 2 + exlen;
                data = (byte*) malloc (sizeof(byte) * length);

                data[count++] = sessionPacket->type;
                data[count++] = versionProtocol;
                for (i = 0; i < 2 && count < length; i++, count++) {
                    data[count] = extraLength[i];
                }

                for (i = 0; i < exlen && count < length; i++, count++) {
                    data[count] = sessionPacket->extra[i];
                }

                free(extraLength);
                break;
            }
            case PACKET_TYPE_SESSION_CLOSE: {
                // 登出
                int count = 0, i;

                ifsessionClosePacket *sessionPacket = (ifsessionClosePacket *) packet;
				int exlen = if_str_len(sessionPacket->extra);
                byte *extraLength = if_shortToByteArray(exlen);

                from = sessionPacket->from;
                to = sessionPacket->to;
                id = sessionPacket->id;

                length = 1 + 2 + exlen;
                data = (byte*) malloc (sizeof(byte) * length);

                data[count++] = sessionPacket->type;

                for (i = 0; i < 2 && count < length; i++, count++) {
                    data[count] = extraLength[i];
                }

                for (i = 0; i < exlen && count < length; i++, count++) {
                    data[count] = sessionPacket->extra[i];
                }

                free(extraLength);
                break;
            }
            case PACKET_TYPE_MESSAGE: {
                ifmessage *message = (ifmessage *) packet;

				int ttlen = if_str_len(message->title);
                byte *titleBytes = (byte*)message->title;
				int bdlen = if_str_len(message->body);
                byte *bodyBytes= (byte*)message->body;
                int count = 1, i;
                byte *lengthBytes = if_intToByteArray(bdlen);

                from = message->from;
                to = message->to;
                id = message->id;

                length = 1 + ttlen + 4 + bdlen;
                data = (byte*) malloc (sizeof(byte) * length);
                data[0] = ttlen;

                for (i = 0; i < ttlen && count < length; i ++, count ++) {
                    data[count] = titleBytes[i];
                }
                for (i = 0; i < 4 && count < length; i ++, count ++) {
                    data[count] = lengthBytes[i];
                }
                for (i = 0; i < bdlen && count < length; i ++, count ++) {
                    data[count] = bodyBytes[i];
                }

                free(lengthBytes);
                break;
            }
            case PACKET_TYPE_EVENT: {
                ifevent *event = (ifevent *) packet;
                byte *eventTypeBytes = if_shortToByteArray(event->eventType);
                byte *actionCodeBytes = if_intToByteArray(event->actionCode);
				int bdlen = if_str_len(event->body);
                byte *bodyBytes = (byte*)event->body;
                int count = 0, i;
                byte *lengthBytes = if_intToByteArray(bdlen);

                from = event->from;
                to = event->to;
                id = event->id;

                length = 2 + 1 + 4 + 4 + bdlen;
                data = (byte*) malloc (sizeof(byte) * length);

                for (i = 0; i < 2 && count < length; i ++, count ++) {
                    data[count] = eventTypeBytes[i];
                }
                data[count++] = event->type;
                // action code
                for (i = 0; i < 4 && count < length; i ++, count ++) {
                    data[count] = actionCodeBytes[i];
                }

                for (i = 0; i < 4 && count < length; i ++, count ++) {
                    data[count] = lengthBytes[i];
                }
                for (i = 0; i < bdlen && count < length; i ++, count ++) {
                    data[count] = bodyBytes[i];
                }

                free(lengthBytes);
                free(actionCodeBytes);
                free(eventTypeBytes);
                break;
            }
        }

        buffer = if_packet_common(from, to, id, packetType, data, length, key);
        free(data);
        return buffer;
    } else {
        return NULL;
    }
}

